﻿using aier.business.logic;
using aier.dataaccess.dapper;
using aier.wx.nosql.redis;
using aier.xrm.wcf;
using Autofac;
using Autofac.Core;
using Autofac.Integration.WebApi;
using log4net;
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using Owin;
using ServiceStack.Redis;

[assembly: OwinStartup(typeof(aier.wx.api.selfhost.Startup))]
namespace aier.wx.api.selfhost
{
    using aier.dataaccess.model;
    using Microsoft.Owin.Security.DataHandler.Encoder;
    using System;
    using System.Configuration;
    using System.IdentityModel.Claims;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Reflection;
    using System.Threading.Tasks;
    using System.Web.Http;
    using LimitsMiddleware;
    using Microsoft.Owin.FileSystems;
    using Microsoft.Owin.StaticFiles;
	using ServiceStack.Text;
	using ServiceStack.Web;

    public class Startup
    {
        // 有关如何配置应用程序的详细信息，请访问 https://go.microsoft.com/fwlink/?LinkID=316888
        public void Configuration(IAppBuilder app)
        {
            var builder = new ContainerBuilder();
            string redisConnectionStr = string.Concat(ConfigurationManager.ConnectionStrings["Aier_RedisNOSQL"].ConnectionString, "&ConnectTimeout=5000&IdleTimeOutSecs=180&PoolTimeout=3");
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
            builder.Register<PooledRedisClientManager>(c=> new PooledRedisClientManager(redisConnectionStr))
                .As<IRedisClientsManager>().SingleInstance();
           
            //依赖注入
            builder.RegisterModule(new LoggingModule());
            builder.RegisterType<RedisClientManager>();
            builder.RegisterType<DapperHelper>();
            builder.RegisterType<ApiTool>();
         


            builder.RegisterType(typeof(HomeDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(AreaDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(UserDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ClassDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(SchoolDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(CampainDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(HospitalDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(AppointmentDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(DepartmentDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenItemDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenCallBackDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(XrmOptionDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenTeamDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenTemplateDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ReservationDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(TaskDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(EquipmentDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ProvinceDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(AreaInfoDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(CityDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(CommunityDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(CompetitorDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(LeadDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(RecommendDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(CategoryDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ContentDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenCustomerDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenResultDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenTSCItemDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(StreetDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenPropagandaDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ContactDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(DoctorDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(SequenceDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(ScreenEquipmentDal)).WithProperty("dapperHelper", new DapperHelper());
            builder.RegisterType(typeof(NetDoctorsStatisticDal)).WithProperty("dapperHelper", new DapperHelper());
            
            builder.RegisterType(typeof(AttachmentDal)).WithProperty("dapperHelper", new DapperHelper(ConfigurationManager.ConnectionStrings["Aier_Mobile_CRMDB"].ConnectionString));
            builder.RegisterType(typeof(CustomerUserDal)).WithProperty("dapperHelper", new DapperHelper(ConfigurationManager.ConnectionStrings["Aier_Mobile_CRMDB"].ConnectionString));
            builder.RegisterType(typeof(ReferralPatientDal)).WithProperty("dapperHelper", new DapperHelper(ConfigurationManager.ConnectionStrings["Aier_Mobile_CRMDB"].ConnectionString));

            builder.RegisterAssemblyTypes(typeof(CommonWcf).Assembly).WithProperty("xrmService", new XrmService());

            builder.RegisterAssemblyTypes(typeof(ResResult).Assembly);
            builder.RegisterType<RedisTestDal>().PropertiesAutowired();



            builder.RegisterType<UserBll>().PropertiesAutowired();
            builder.RegisterType<TaskBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<HomeBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<AreaBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<CampainBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<HospitalBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<AppointmentBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<StreetBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<DepartmentBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenItemBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenCallBackBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenTypeBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenTeamBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenTemplateBll>().PropertiesAutowired();
            builder.RegisterType<ReservationBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<CommonUtil>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ClassBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<SchoolBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ProvinceBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<AreaInfoBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<CityBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<CommunityBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<CompetitorBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<LeadBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<RecommendBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<AttachmentBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ContactBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<RefreshTokenService>().As<IRefreshTokenService>();
            builder.RegisterType<RefreshTokenRedisRepository>().As<IRefreshTokenRepository>();
            builder.RegisterType<StoreRefreshTokenProvider>();
            builder.RegisterType<CategoryBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<DoctorBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ContentBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenCustomerBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenResultBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<CommonBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenPropagandaBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ChineseToLetterBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<SequenceBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<ScreenEquipmentBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<NetDoctorsStatisticBll>().PropertiesAutowired().InstancePerRequest();
            builder.RegisterType<IdentityCardOcrBll>().PropertiesAutowired()
                   .WithProperty("accessKeyId", ConfigurationManager.AppSettings["accessKeyId"])
                   .WithProperty("accessSecret", ConfigurationManager.AppSettings["accessSecret"])
                   .WithProperty("endpoint", ConfigurationManager.AppSettings["endpoint"]).InstancePerRequest();

            HttpConfiguration httpConfig = new HttpConfiguration();
			//swagger注释
			if (bool.TryParse(ConfigurationManager.AppSettings["swaggerUI"], out bool swaggerUI)
				&& swaggerUI)
			{
				SwaggerConfig.Register(httpConfig);
			}
			WebApiConfig.Register(httpConfig);

            
            

            var container = builder.Build();
            httpConfig.DependencyResolver = new AutofacWebApiDependencyResolver(container);
			

			ConfigOAuth(app, container);
		
			app.Use(Limits.MaxRequestContentLength(int.MaxValue));
            app.UseAutofacMiddleware(container);
            app.UseAutofacWebApi(httpConfig);

			#region
			//静态网站根目录
			//var physicalFileSystem = new PhysicalFileSystem(@".\wwwroot");
			//var options = new FileServerOptions
			//{
			//	EnableDefaultFiles = true,
			//	FileSystem = physicalFileSystem
			//};
			//options.StaticFileOptions.OnPrepareResponse = (StaticFileResponseContext) =>
			//{
			//	if (StaticFileResponseContext.File.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
			//		StaticFileResponseContext.OwinContext.Response.Headers.Add("Content-type", new[] { "application/json", "charset=UTF-8" });
			//};
			//options.StaticFileOptions.FileSystem = physicalFileSystem;
			//options.StaticFileOptions.ServeUnknownFileTypes = true;
			//app.UseFileServer(options);
			#endregion
			RegisterStaticFileServer(app);
        
			app.UseWebApi(httpConfig);
			
		}

		private void RegisterStaticFileServer(IAppBuilder app)
        {
			var physicalFileSystem = new PhysicalFileSystem(@".\wwwroot");
			var options = new FileServerOptions
			{
				EnableDefaultFiles = true,
				FileSystem = physicalFileSystem
			};
			options.StaticFileOptions.OnPrepareResponse = (StaticFileResponseContext) =>
			{
				if (StaticFileResponseContext.File.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
					StaticFileResponseContext.OwinContext.Response.Headers.Add("Content-type", new[] { "application/json", "charset=UTF-8" });
			};
			options.StaticFileOptions.FileSystem = physicalFileSystem;
			options.StaticFileOptions.ServeUnknownFileTypes = true;
			app.UseFileServer(options);
		}


		public void ConfigOAuth(IAppBuilder app, IContainer container)
        {
            UserBll userBll = container.Resolve<UserBll>();
            //"IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw"
            var secretStr = ConfigurationManager.AppSettings["SecretKey"];
            var secret = TextEncodings.Base64Url.Decode(secretStr);//秘钥
            var issuer = ConfigurationManager.AppSettings["Issuer"]; //"http://localhost:2817/";

            OAuthAuthorizationServerOptions option = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new AuthorizationServerProvider(userBll),
                //刷新令牌服务暂时项目不用使用
                //RefreshTokenProvider = container.Resolve<StoreRefreshTokenProvider>(),
                AccessTokenFormat = new CustomJwtFormat(issuer, secret)
            };
            app.UseOAuthAuthorizationServer(option);
		

			app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
            {
                Provider = new OAuthBearerAuthenticationProvider()
                {
                    OnValidateIdentity = context =>
                    {
                        context.Ticket.Identity.AddClaim(new System.Security.Claims.Claim(ClaimTypes.NameIdentifier, context.Ticket.Identity.Name));
                        return Task.CompletedTask;
                        //return Task.FromResult<object>(context);
                    },
                    OnRequestToken = (context) =>
                    {
                        if (context.Token != null)
                        {
                            context.Response.Headers["WWW-Authorization"] = "Bearer";

                            var jst = new JwtSecurityTokenHandler();
                            var token = (JwtSecurityToken)jst.ReadToken(context.Token);
                            //创建身份
                            var identity = new System.Security.Claims.ClaimsIdentity(token.Claims, "JWT");
                            context.Request.User = new System.Security.Claims.ClaimsPrincipal(identity);

                        }
                        return Task.CompletedTask;
                        //return Task.FromResult<object>(context);
                    },
                    OnApplyChallenge= (context) => {
                        if (context.Request.Uri.PathAndQuery.EndsWith("swagger/ui/index"))
                        {
                            context.Request.Headers["WWW-Authenticate"] = context.Challenge;
                        }
                        else {
							context.OwinContext.Response.Headers.AppendValues("WWW-Authenticate", context.Challenge);
						}
						return Task.CompletedTask;
					}
				}
            });

         


        }
    }

    public class LoggingModule : Autofac.Module
    {
        private static void InjectLoggerProperties(object instance)
        {
            var instanceType = instance.GetType();

            // Get all the injectable properties to set.
            // If you wanted to ensure the properties were only UNSET properties,
            // here's where you'd do it.
            var properties = instanceType
              .GetProperties(BindingFlags.Public | BindingFlags.Instance)
              .Where(p => p.PropertyType == typeof(ILog) && p.CanWrite && p.GetIndexParameters().Length == 0);

            // Set the properties located.
            foreach (var propToSet in properties)
            {
                propToSet.SetValue(instance, LogManager.GetLogger(instanceType), null);
            }
        }

        private static void OnComponentPreparing(object sender, PreparingEventArgs e)
        {
            e.Parameters = e.Parameters.Union(
              new[]
              {
                new ResolvedParameter(
                    (p, i) => p.ParameterType == typeof(ILog),
                    (p, i) => LogManager.GetLogger(p.Member.DeclaringType)
                ),
              });
        }

        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
        {
            // Handle constructor parameters.
            registration.Preparing += OnComponentPreparing;

            // Handle properties.
            registration.Activated += (sender, e) => InjectLoggerProperties(e.Instance);
        }
    }
}
